﻿using Jinjia.Approve.IService.JJFlow.BPM;
using Jinjia.Approve.Model.VM;
using Jinjia.Approve.Model.VM.JJFlow;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using JinJia.Core.Base.Exceptions;

namespace Jinjia.Approve.Service.JJFlow.BPM
{
    public class JJFlowBpmXMLParserService : IJJFlowBpmXMLParserService
    {
        private List<string> nodeIds;

        /// <summary>
        /// 将xml转换为节点和步骤转换为模型
        /// </summary>
        /// <param name="bpmXml"></param>
        public JJFlowBPMProcessVM ParseXmlToModel(string bpmXml)
        {
            nodeIds = new List<string>();
            //加载xml
            XmlDocument bpmn_xml = new XmlDocument();
            bpmn_xml.LoadXml(bpmXml);
            //根据根节点数据解析，如果流程有问题，会抛出异常
            return ParseXml(bpmn_xml.DocumentElement);
        }

        private JJFlowBPMProcessVM ParseXml(XmlElement xmlRoot)
        {
            JJFlowBPMProcessVM processModel = new JJFlowBPMProcessVM();
            int processCount = 0;
            foreach (XmlNode node in xmlRoot.ChildNodes)
            {
                if (node.Name == "process")
                {
                    if (processCount > 1)
                    {
                        throw new BusinessException("流程不符合规范，转换失败，多个流程定义process");
                    }
                    processCount++;
                    processModel = ParseProcess(node);
                }
            }
            return processModel;
        }

        /// <summary>
        /// 根据xml将所有的nodes, steps解析出来
        /// 目前五种类型
        /// </summary>
        /// <param name="process_node"></param>
        private JJFlowBPMProcessVM ParseProcess(XmlNode process_node)
        {
            JJFlowBPMProcessVM processModel = new JJFlowBPMProcessVM();
            int startEnventCount = 0;

            //节点
            foreach (XmlNode node in process_node.ChildNodes)
            {
                if (node.Name == "startEvent")
                {
                    if (startEnventCount > 1)
                    {
                        throw new BusinessException("流程不符合规范，转换失败，多个开始节点startEnvent");
                    }
                    processModel.StartEvent = ParseStartEventNode(node);
                    startEnventCount++;
                }

                //if判断
                if (node.Name == "exclusiveGateway")
                {
                    processModel.ExclusiveGateways.Add(ParseExclusiveGatewayNode(node));
                }
                if (node.Name == "endEvent")
                {
                    processModel.EndEvents.Add(ParseEndEventNode(node));
                }
                if (node.Name == "userTask")
                {
                    processModel.UserTasks.Add(ParseUserTaskNode(node));
                }
            }
            //连线
            foreach (XmlNode node in process_node.ChildNodes)
            {
                if (node.Name == "sequenceFlow")
                {
                    processModel.SequenceFlows.Add(ParseSequenceFlowNode(node));
                }
            }

            //计算节点步骤 下一节点

            processModel.NodeList.Add(processModel.StartEvent.id, 1);

            GetNextNode(processModel.StartEvent.id, processModel.SequenceFlows, processModel.NodeList, processModel.TargetList);

            return processModel;
        }

        private void GetNextNode(string strartNodeId, List<JJFlowBPMSequenceFlowVM> sequence, Dictionary<string, int> nodeList, Dictionary<string, List<string>> targetList)
        {
            var nextNodeList = sequence.Where(t => t.sourceRef == strartNodeId);
            foreach (var item in nextNodeList)
            {
                if (nodeList.ContainsKey(item.targetRef))
                {
                    if (nodeList[item.targetRef] < nodeList[item.sourceRef] + 1)
                    {
                        nodeList[item.targetRef] = nodeList[item.sourceRef] + 1;
                    }
                }
                else
                {
                    nodeList.Add(item.targetRef, nodeList[item.sourceRef] + 1);
                }

                if (targetList.ContainsKey(item.sourceRef))
                {
                    targetList[item.sourceRef].Add(item.targetRef);
                }
                else
                {
                    targetList.Add(item.sourceRef, new List<string>() { item.targetRef });
                }

                GetNextNode(item.targetRef, sequence, nodeList, targetList);
            }
        }

        #region 解析节点

        /// <summary>
        /// 解析开始节点
        /// </summary>
        /// <param name="node"></param>
        private JJFlowBPMStartEventVM ParseStartEventNode(XmlNode node)
        {
            JJFlowBPMStartEventVM startEvent = new JJFlowBPMStartEventVM();
            nodeIds.Add(node.Attributes["id"].Value);

            startEvent.id = node.Attributes["id"].Value;
            if (node.Attributes["name"] != null)
            {
                startEvent.name = node.Attributes["name"].Value;
            }

            foreach (XmlNode item in node.ChildNodes)
            {
                if (item.Name == "documentation")
                {
                    startEvent.remark = item.InnerText;
                }
            }

            return startEvent;
        }

        /// <summary>
        /// 解析结束节点
        /// </summary>
        /// <param name="node"></param>
        private JJFlowBPMEndEventVM ParseEndEventNode(XmlNode node)
        {
            nodeIds.Add(node.Attributes["id"].Value);

            JJFlowBPMEndEventVM endEvent = new JJFlowBPMEndEventVM();
            endEvent.id = node.Attributes["id"].Value;
            endEvent.name = node.Attributes["name"].Value;

            foreach (XmlNode item in node.ChildNodes)
            {
                if (item.Name == "documentation")
                {
                    endEvent.remark = item.InnerText;
                }
            }

            return endEvent;
        }

        /// <summary>
        /// 解析用户任务节点
        /// </summary>
        /// <param name="node"></param>
        private JJFlowBPMUserTaskVM ParseUserTaskNode(XmlNode node)
        {
            nodeIds.Add(node.Attributes["id"].Value);

            JJFlowBPMUserTaskVM userTask = new JJFlowBPMUserTaskVM();
            userTask.id = node.Attributes["id"].Value;
            userTask.name = node.Attributes["name"].Value;

            userTask.userIdList = new List<int>();
            userTask.action = new List<int>();
            userTask.roleIdList = new List<string>();

            foreach (XmlNode itemExtensionElements in node.ChildNodes)
            {
                if (itemExtensionElements.Name == "extensionElements")
                {
                    foreach (XmlNode itemFlowable in itemExtensionElements.ChildNodes)
                    {
                        if (itemFlowable.Name == "flowable:customProperties")
                        {
                            #region 审核人员类型

                            //审核人员类型
                            int findUserType = 0;
                            int.TryParse(itemFlowable.Attributes["findUserType"].Value, out findUserType);
                            userTask.power_type = findUserType;

                            //角色
                            if (itemFlowable.Attributes["roleCode"] != null)
                            {
                                var roleIdStr = itemFlowable.Attributes["roleCode"].Value;
                                var roleIdListStr = roleIdStr.Split(',');
                                foreach (var item in roleIdListStr)
                                {
                                    if (!string.IsNullOrWhiteSpace(item))
                                    {
                                        if (!userTask.roleIdList.Contains(item))
                                        {
                                            userTask.roleIdList.Add(item);
                                        }
                                    }
                                }
                            }

                            //指定人员
                            if (itemFlowable.Attributes["userIdList"] != null)
                            {
                                var useIdStr = itemFlowable.Attributes["userIdList"].Value;
                                var useIdListStr = useIdStr.Split(',');
                                foreach (var item in useIdListStr)
                                {
                                    int useId = 0;
                                    if (int.TryParse(item, out useId))
                                    {
                                        if (!userTask.userIdList.Contains(useId))
                                        {
                                            userTask.userIdList.Add(useId);
                                        }
                                    }
                                }
                            }

                            //方法名称
                            if (itemFlowable.Attributes["assigneeField"] != null)
                            {
                                userTask.assigneeField = itemFlowable.Attributes["assigneeField"].Value;
                            }

                            //组织架构
                            if (itemFlowable.Attributes["orgLevel"] != null)
                            {
                                userTask.orgLevel = itemFlowable.Attributes["orgLevel"].Value;
                            }

                            #endregion

                            #region 完成策略  会签  或签

                            if (itemFlowable.Attributes["signType"] != null)
                            {
                                int signType = 0;
                                int.TryParse(itemFlowable.Attributes["signType"].Value, out signType);
                                userTask.signType = signType;
                            }

                            #endregion

                            #region 节点按钮

                            var actionListStr = itemFlowable.Attributes["actionList"].Value;
                            var actionList = actionListStr.Split(',');
                            int actionType = 0;

                            foreach (var item in actionList)
                            {
                                int.TryParse(actionList[0], out actionType);
                                if (!userTask.action.Contains(actionType))
                                {
                                    userTask.action.Add(actionType);
                                }
                            }

                            #endregion

                            #region 节点规则

                            if (itemFlowable.Attributes["autoApprove"] != null)
                            {
                                userTask.auto_approve = Convert.ToInt32(itemFlowable.Attributes["autoApprove"].Value);
                            }
                            if (itemFlowable.Attributes["approveRule"] != null)
                            {
                                userTask.approve_rule = itemFlowable.Attributes["approveRule"].Value;
                            }
                            if (itemFlowable.Attributes["rejectRule"] != null)
                            {
                                userTask.reject_rule = itemFlowable.Attributes["rejectRule"].Value;
                            }
                            #endregion

                            break;
                        }
                    }
                    break;
                }
                else if (itemExtensionElements.Name == "documentation")
                {
                    userTask.remark = itemExtensionElements.InnerText;
                }
            }

            return userTask;
        }

        /// <summary>
        /// 解析用户任务节点
        /// </summary>
        /// <param name="node"></param>
        private JJFlowBPMExclusiveGatewayVM ParseExclusiveGatewayNode(XmlNode node)
        {
            nodeIds.Add(node.Attributes["id"].Value);

            JJFlowBPMExclusiveGatewayVM exclusiveGateways = new JJFlowBPMExclusiveGatewayVM();
            exclusiveGateways.id = node.Attributes["id"].Value;
            exclusiveGateways.name = node.Attributes["name"].Value;

            foreach (XmlNode item in node.ChildNodes)
            {
                if (item.Name == "documentation")
                {
                    exclusiveGateways.remark = item.InnerText;
                }
            }

            //解析 incoming   outgoing

            return exclusiveGateways;
        }

        /// <summary>
        /// 解析连线
        /// </summary>
        /// <param name="node"></param>
        private JJFlowBPMSequenceFlowVM ParseSequenceFlowNode(XmlNode node)
        {
            JJFlowBPMSequenceFlowVM sequenceFlow = new JJFlowBPMSequenceFlowVM();
            sequenceFlow.id = node.Attributes["id"].Value;
            if (node.Attributes["name"] != null)
            {
                sequenceFlow.remark = node.Attributes["name"].Value;
            }
            if (node.Attributes["priority"] != null)
            {
                sequenceFlow.priority = Convert.ToInt32(node.Attributes["priority"].Value);
            }
            sequenceFlow.sourceRef = node.Attributes["sourceRef"].Value;
            sequenceFlow.targetRef = node.Attributes["targetRef"].Value;

            if (node.Attributes["conditiontype"] != null)
            {
                sequenceFlow.condition_type = node.Attributes["conditiontype"].Value;
            }

            foreach (XmlNode item in node.ChildNodes)
            {
                if (item.Name == "conditionExpression")
                {
                    sequenceFlow.condition_name = item.InnerText;
                }
            }

            //节点连线   没有连
            if (!nodeIds.Contains(sequenceFlow.sourceRef) || !nodeIds.Contains(sequenceFlow.targetRef))
            {
                throw new BusinessException("流程不符合规范，转换失败，节点未正常连接");
            }

            return sequenceFlow;
        }

        #endregion

        public XmlDocument BPMReplaceUserIdList(string xml, string handoverUserId, string userId)
        {
            try
            {
                XmlDocument bpmnXml = new XmlDocument();
                bpmnXml.LoadXml(xml);

                //添加命名空间
                XmlNamespaceManager xmlNamespace = new XmlNamespaceManager(bpmnXml.NameTable);
                xmlNamespace.AddNamespace("flowable", "http://flowable.org/bpmn");
                //获取节点
                var nodeList = bpmnXml.DocumentElement
                    .SelectNodes("//flowable:customProperties[@userIdList != '']", xmlNamespace)//使用XPath获取节点
                    .Cast<XmlNode>()
                    .ToList();

                var isUpdate = false;
                foreach (var item in nodeList)
                {
                    #region 人员替换

                    var property = item.Attributes.GetNamedItem("userIdList");
                    if (property == null)
                    {
                        continue;
                    }
                    var userIdList = property.Value.Split(',').ToList();
                    var index = userIdList.FindIndex(m => m == userId);
                    if (index < 0)
                    {
                        continue;
                    }
                    userIdList[index] = handoverUserId;
                    property.Value = string.Join(",", userIdList);

                    #endregion

                    //标记已修改
                    if (!isUpdate)
                        isUpdate = true;
                }
                return isUpdate ? bpmnXml : null;
            }
            catch
            {
                return null;
            }
        }
    }
}